(function () {

	function rand(min, max) {
		return min + Math.round(Math.random() * (max - min));
	}

	function getRandElements(elements, num) {
		var result = [];
		for (var i = 0; i < num; i++) {
			result.push(elements[rand(0, elements.length - 1)])
		}
		return result;
	}

	function dummyFunction() {
	}


//	#region GameLogo

	function GameLogo() {
		this.obj = $('<div/>').addClass('game-logo');
	}

//	#endregion


//	#region GamePayline

	function GamePayline(name) {
		this.name = name;
		this.isActive = false;
		this.isHighlited = false;

		var highlighter = $('<div/>').addClass('game-payline-highlighter');
		this.obj = $('<div/>').addClass('game-payline').addClass('game-payline-' + name).append(highlighter);
	}

	GamePayline.prototype.highliteOn = function (timeout) {
		if (this.isHighlited) {
			return;
		}

		this.isHighlited = true;
		this.obj.addClass('game-payline-highlighted').addClass('game-payline-' + this.name + '-highlighted');
	};

	GamePayline.prototype.highliteOff = function (timeout) {
		if (!this.isHighlited) {
			return;
		}

		this.isHighlited = false;
		this.obj.removeClass('game-payline-highlighted').removeClass('game-payline-' + this.name + '-highlighted');
	};

	GamePayline.prototype.activate = function () {
		this.isActive = true;
		this.obj.addClass('game-payline-active').addClass('game-payline-' + this.name + '-active');
	};

	GamePayline.prototype.deactivate = function () {
		this.isActive = false;
		this.obj.removeClass('game-payline-active').removeClass('game-payline-' + this.name + '-active');
	};

//	#endregion


//	#region GamePaylineMap


	function GamePaylineMap(name, childsNum) {
		this.name = name;
		this.obj = $('<div/>').addClass('game-paylineMap').addClass('game-paylineMap-' + name);
		for (var i = 0; i < childsNum; i++) {
			var child = $('<div/>').addClass('game-paylineMap-child').addClass('game-paylineMap-child-' + i);
			this.obj.append(child);
		}
	}

	GamePaylineMap.prototype.show = function () {
		this.obj.addClass('game-paylineMap-visible');
	};

	GamePaylineMap.prototype.hide = function () {
		this.obj.removeClass('game-paylineMap-visible');
	};

//	#endregion


//	#region GameRollElement

	function GameRollElement(name) {
		this.name = name;

		this.obj = $('<div/>').addClass('game-roll-element').addClass('game-roll-element-' + name);
	}

//	#endregion


//	#region GameRoll

	function GameRoll(num, size, elementNames) {
		this.num = num;
		this.size = size;

		this.obj = $('<div/>').addClass('game-roll').addClass('game-roll-' + num);
		this.elementsBox = $('<div/>').addClass('game-roll-box');
		this.elementNames = elementNames;
		this.elements = [];

		this.renewElements();

		this.obj.append(this.elementsBox);
	}

	GameRoll.prototype.getContent = function () {
		var result = [];
		for (var i = 1, iLength = this.elements.length - 1; i < iLength; i++) {
			result.push(this.elements[i].name);
		}
		return result;
	};

	GameRoll.prototype.renewElements = function () {
		this.elementsBox.empty();
		this.elements = [];

		var elementsSet = getRandElements(this.elementNames, this.size + 2);
		for (var i = 0; i < this.size + 2; i++) {
			var element = new GameRollElement(elementsSet[i]);
			this.elementsBox.append(element.obj);
			this.elements.push(element);
		}
	};

	GameRoll.prototype.startSpin = function () {
		this.obj.removeClass('game-roll-spinning-stop').addClass('game-roll-spinning').addClass('game-roll-spinning-start');
	};

	GameRoll.prototype.stopSpin = function () {
		this.renewElements();
		this.obj.removeClass('game-roll-spinning').removeClass('game-roll-spinning-start').addClass('game-roll-spinning-stop');
	};


//	#endregion


//	#region GameButton

	function GameButton(name, onClick) {
		this.onClick = onClick || dummyFunction;
		this.isEnabled = true;
		this.name = name;

		var _this = this;
		this.obj = $('<div/>').addClass('game-' + this.name + '-button').click(function () {
			if (_this.isEnabled) {
				_this.onClick();
			}
		});
	}

	GameButton.prototype.disable = function () {
		this.isEnabled = false;
		this.obj.addClass('game-button-disabled').addClass('game-' + this.name + '-button-disabled');
	};

	GameButton.prototype.enable = function () {
		this.isEnabled = true;
		this.obj.removeClass('game-button-disabled').removeClass('game-' + this.name + '-button-disabled');
	};

//	#endregion


// #region Denomination Table

	function DenominationNumber(digit) {
		this.digit = digit;
		this.indent = -16;
		this.imageWidth = -16;
		this.Render();
	}

	DenominationNumber.prototype.Render = function() {
		var leftIndent = this.digit * this.imageWidth + this.indent;
		this.objNum = $('<div></div>').addClass('game-denomination-number')
			.css('background-position', leftIndent + 'px 8px');
	};

	function DenominationTable(num) {
		this.obj = $('<div class="game-denomination-table"></div>');
		this.ParseNumber(num);
	}

	DenominationTable.prototype.ParseNumber = function(num) {
		var str = num + '';
		this.obj.empty();
		for(var i = 0; i < str.length; i++) {
			var digit = new DenominationNumber(parseInt(str[i]));
			this.obj.append(digit.objNum);
		}
	};

	DenominationTable.prototype.Set = function(num, callback) {
		this.ParseNumber(num);
		if(typeof(callback) == 'function') {
			callback();
		}
	};

// # endregion


// #region Bonus Points

	function BonusPointNumber (digit) {
		this.digit = digit;
		this.indent = -17;
		this.imageWidth = -17;
		this.Render();
	}

	BonusPointNumber.prototype.Render = function() {
		var leftIndent = this.digit * this.imageWidth + this.indent;
		this.objNum = $('<div></div>').addClass('game-bonus-point-number')
			.css('background-position', leftIndent + 'px 8px');
	};

	function BonusPointTable(num) {
		this.obj = $('<div class="game-bonus-point-table"></div>');
		this.ParseNumber(num);
	}

	BonusPointTable.prototype.ParseNumber = function(num) {
		var str = num + '';
		this.obj.empty();
		for(var i = 0; i < str.length; i++) {
			var digit = new BonusPointNumber(parseInt(str[i]));
			this.obj.append(digit.objNum);
		}
	};

	BonusPointTable.prototype.Set = function(num, callback) {
		this.ParseNumber(num);
		if(typeof(callback) == 'function') {
			callback();
		}
	};

// #endregion


//	#region Game

	function Game(objSelector) {
		this.obj = $(objSelector);
		if (!this.obj.length) {
			throw "Invalid object selector";
		}
		this.obj.addClass('game');
	}

	Game.prototype.setState = function(state)
	{
		var states = ['loading', 'ready', 'playing'];
		if(states.indexOf(state) > -1)
		{
			for (var i = 0, iLength = states.length; i < iLength; i++) {
				this.obj.removeClass('game-state-' + states[i]);
			}
			this.obj.addClass('game-state-' + state);
		}
	};

	Game.prototype.init = function()
	{
		this.rollsNumber = 5;
		this.rollsElements = ['ace', 'jack'];//, 'queen', 'king', 'ten', 'nine', 'jackpot', 'harp', 'scatter'];


		// Rolls
		this.rollingPeriod = 2000;
		this.rollsSpinDelay = 250;
		this.rolls = [];


		// Paylines

		this.numberOfLinesMax = 3;
		this.numberOfLines = 2;
		this.numberOfLinesMin = 1;

		this.paylinesHighlitePeriod = 1000;
		this.paylinesNames = [4, 2, 6, 8, 1, 9, 7, 3, 5];
		this.paylinesNumber = this.paylinesNames.length;
		this.paylineHighliteDelay = Math.round(this.paylinesHighlitePeriod / this.paylinesNumber);
		this.paylines = [];


		// Payline maps

		this.paylineMaps = [];


		this.denominationTable = new DenominationTable(this.numberOfLines);

		this.bonusPointTable = new BonusPointTable(42051);


		var _this = this;
		this.loadResources(function(){
			_this.generateContent();
			_this.show();
		});
	};

	Game.prototype.generateContent = function()
	{
		var _game = this;

		// Logo
		this.logo = new GameLogo();
		this.obj.append(this.logo.obj);

		// Rolls
		this.objRolls = $('<div/>').addClass('game-rolls');
		for (var i = 0; i < this.rollsNumber; i++) {
			var roll = new GameRoll(i, 3, this.rollsElements);
			this.objRolls.append(roll.obj);
			this.rolls.push(roll);
		}
		this.obj.append(this.objRolls);

		// Paylines
		this.objPaylines = $('<div/>').addClass('game-paylines');
		for (var i = 0; i < this.paylinesNumber; i++) {
			var name = this.paylinesNames[i];
			var payline = new GamePayline(name);
			this.objPaylines.append(payline.obj);
			this.paylines[name] = payline;
		}
		this.obj.append(this.objPaylines);

		// Paylines maps
		this.objPaylineMaps = $('<div/>').addClass('game-paylineMaps');
		for (var i = 0; i < this.paylinesNumber; i++) {
			var name = this.paylinesNames[i];
			var paylineMap = new GamePaylineMap(name, this.rollsNumber);
			this.objPaylineMaps.append(paylineMap.obj);
			this.paylineMaps[name] = paylineMap;
		}
		this.obj.append(this.objPaylineMaps);

		// Buttons
		this.paytableButton = new GameButton('paytable', function () {
			_game.startSpin();

			window.setTimeout(function () {
				_game.stopSpin();
			}, _game.rollingPeriod);
		});
		this.obj.append(this.paytableButton.obj);

		this.denominationIncButton = new GameButton('deniminationInc', function () {
			_game.denominationInc();
		});
		this.obj.append(this.denominationIncButton.obj);

		this.denominationDecButton = new GameButton('deniminationDec', function () {
			_game.denominationDec();
		});
		this.obj.append(this.denominationDecButton.obj);

		this.obj.append(this.denominationTable.obj);

		this.obj.append(this.bonusPointTable.obj);
	};

	Game.prototype.show = function()
	{
		this.setState('ready');


		this.highlitePaylines();
		this.showActiveLines(this.numberOfLines);
	};

	Game.prototype.loadResources = function(callback)
	{
		callback = callback || dummyFunction;
		this.setState('loading');

		var images = [
			'images/game_ims_payline_1.png',
			'images/game_ims_payline_2.png',
			'images/game_ims_payline_3.png',
			'images/game_ims_reels_blurred.png',
			'images/game_ims_a_symbol_animation.png',
			'images/game_ims_k_symbol_animation.png',
			'images/game_ims_q_symbol_animation.png',
			'images/game_ims_j_symbol_animation.png',
			'images/game_ims_10_symbol_animation.png',
			'images/game_ims_9_symbol_animation.png'
		];

		var loader = new PxLoader();

		for (var i = 0, iLength = images.length; i < iLength; i++) {
			loader.addImage(images[i]);
	}

		loader.addProgressListener(function(e) {
			window.console && window.console.log(e.completedCount + ' / ' + e.totalCount);
		});

		var _this = this;

		loader.addCompletionListener(function() {
			callback();
		});

		loader.start();
	};


	Game.prototype.showActiveLines = function () {
		for (var i = 0; i < this.paylinesNumber; i++) {
			var name = this.paylinesNames[i];
			if (name <= this.numberOfLines) {
				this.paylines[name].activate();
			}
			else {
				this.paylines[name].deactivate();
			}
		}

		this.numberOfLines == this.numberOfLinesMin ? this.denominationDecButton.disable() : this.denominationDecButton.enable();
		this.numberOfLines == this.numberOfLinesMax ? this.denominationIncButton.disable() : this.denominationIncButton.enable();

		this.denominationTable.Set(this.numberOfLines);
	};

	Game.prototype.showActiveLineMaps = function () {
		for (var i = 0; i < this.paylinesNumber; i++) {
			var name = this.paylinesNames[i];
			if (name <= this.numberOfLines) {
				this.paylineMaps[name].show();
			}
			else {
				this.paylineMaps[name].hide();
			}
		}
	};

	Game.prototype.hideActiveLineMaps = function () {
		for (var i = 0; i < this.paylinesNumber; i++) {
			var name = this.paylinesNames[i];
			this.paylineMaps[name].hide();
		}
	};


	Game.prototype.startSpin = function () {
		this.hideActiveLineMaps();
		this.paytableButton.disable();

		for (var i = 0; i < this.rollsNumber; i++) {
			this.rolls[i].startSpin();
		}
	};

	Game.prototype.stopSpin = function () {
		for (var i = 0; i < this.rollsNumber; i++) {
			this.rolls[i].stopSpin();
		}

		var spinResults = [];
		for (var i = 0; i < this.rollsNumber; i++) {
			spinResults.push(this.rolls[i].getContent());
		}

		for (var i = 1; i <= this.numberOfLines; i++) {
			if(this.checkLine(i, spinResults))
			{
				this.paylineMaps[i].show();
			}
		}

		this.paytableButton.enable();
	};

	Game.prototype.checkLine = function (paylineName, spinResults) {
		switch (paylineName) {
			case 1:
			case 2:
			case 3:
				var rowNum = paylineName == 2 ? 0 : (paylineName == 1 ? 1 : 2);
				var value = spinResults[0][rowNum];
				for (var spinNum = 1, spinsLength = spinResults.length; spinNum < spinsLength; spinNum++) {
					if (spinResults[spinNum][rowNum] != value) {
						return false;
					}
				}

				return true;
		}
		return false;
	};

	Game.prototype.denominationInc = function () {
		switch (this.numberOfLines) {
			case 1:
				this.numberOfLines = 2;
				break;
			case 2:
				this.numberOfLines = 3;
				break;
			case 3:
				this.numberOfLines = 5;
				break;
			case 5:
				this.numberOfLines = 7;
				break;
		}
		this.showActiveLines();
		this.showActiveLineMaps();
	};

	Game.prototype.denominationDec = function () {
		switch (this.numberOfLines) {
			case 2:
				this.numberOfLines = 1;
				break;
			case 3:
				this.numberOfLines = 2;
				break;
			case 5:
				this.numberOfLines = 3;
				break;
			case 7:
				this.numberOfLines = 5;
				break;
		}

		this.showActiveLines();
		this.showActiveLineMaps();
	};

	Game.prototype.startPaylinesHighlight = function () {
		this.objPaylines.addClass('game-paylines-highlight');
	};

	Game.prototype.highlitePaylines = function () {
		var _this = this;
		for (var i = 0; i < this.paylinesNumber; i++) {
//			(function (i) {
//				window.setTimeout(function () {
					var name = _this.paylinesNames[i];
					_this.paylines[name].highliteOn(_this.paylineHighliteDelay);
//				}, i * _this.paylineHighliteDelay);
//			})(i);
		}
	};

	// #endregion

	$(function () {



		var game = new Game('#game');
		game.init();
		});

})();